`include "common_defines.v"
module SimTop(
  input                               clock,
  input                               reset,

  input  [63:0]                       io_logCtrl_log_begin,
  input  [63:0]                       io_logCtrl_log_end,
  input  [63:0]                       io_logCtrl_log_level,
  input                               io_perfInfo_clean,
  input                               io_perfInfo_dump,

  output                              io_uart_out_valid,
  output [7:0]                        io_uart_out_ch,
  output                              io_uart_in_valid,
  input  [7:0]                        io_uart_in_ch
);

assign  io_uart_out_valid = 'd0;
assign  io_uart_out_ch    = 'd0;
assign  io_uart_in_valid  = 'd0;

wire               axi_ar_ready  ;
wire               axi_ar_valid  ;
wire  [31:0]       axi_ar_addr   ;
wire  [2:0]        axi_ar_prot   ;
wire  [3:0]        axi_ar_id     ;
wire  [0:0]        axi_ar_user   ;
wire  [7:0]        axi_ar_len    ;
wire  [2:0]        axi_ar_size   ;
wire  [1:0]        axi_ar_burst  ;
wire               axi_ar_lock   ;
wire  [3:0]        axi_ar_cache  ;
wire  [3:0]        axi_ar_qos    ;
wire               axi_r_ready   ;
wire               axi_r_valid   ;
wire  [1:0]        axi_r_resp    ;
wire  [63:0]       axi_r_data    ;
wire               axi_r_last    ;
wire  [3:0]        axi_r_id      ;
wire  [0:0]        axi_r_user    ;
wire               axi_aw_ready  ;       
wire               axi_aw_valid  ;   
wire  [31:0]       axi_aw_addr   ;   
wire  [2:0]        axi_aw_prot   ;   
wire  [3:0]        axi_aw_id     ;
wire  [0:0]        axi_aw_user   ;     
wire  [7:0]        axi_aw_len    ;      
wire  [2:0]        axi_aw_size   ;
wire  [1:0]        axi_aw_burst  ;
wire               axi_aw_lock   ;   
wire  [3:0]        axi_aw_cache  ;   
wire  [3:0]        axi_aw_qos    ;   
wire               axi_w_ready   ;  
wire               axi_w_valid   ;
wire  [63:0]       axi_w_data    ;   
wire  [7:0]        axi_w_strb    ;   
wire               axi_w_last    ;   
wire               axi_b_ready   ;
wire               axi_b_valid   ;
wire  [1:0]        axi_b_resp    ;  
wire  [3:0]        axi_b_id      ;
wire  [0:0]        axi_b_user    ; 

  Rena_ooo CPUcore(
  .clk   ( clock),
  .rst_n (~reset),
  // 用户定义的可屏蔽中断 不影响核心运行的中断
  .user_interrupt(1'b0),
  // 不可屏蔽的关键中断 例如 UPS断电信号 核心外设错误信号
  .sys_interrupt (1'b0),
  /* boot  */
  .boot_addr(`START_ADDR),
  .axi_ar_ready  (axi_ar_ready ),
  .axi_ar_valid  (axi_ar_valid ),
  .axi_ar_addr   (axi_ar_addr  ),
  .axi_ar_prot   (axi_ar_prot  ),
  .axi_ar_id     (axi_ar_id    ),
  .axi_ar_user   (axi_ar_user  ),
  .axi_ar_len    (axi_ar_len   ),
  .axi_ar_size   (axi_ar_size  ),
  .axi_ar_burst  (axi_ar_burst ),
  .axi_ar_lock   (axi_ar_lock  ),
  .axi_ar_cache  (axi_ar_cache ),
  .axi_ar_qos    (axi_ar_qos   ),
  .axi_r_ready   (axi_r_ready ),
  .axi_r_valid   (axi_r_valid ),
  .axi_r_resp    (axi_r_resp  ),
  .axi_r_data    (axi_r_data  ),
  .axi_r_last    (axi_r_last  ),
  .axi_r_id      (axi_r_id    ),
  .axi_r_user    (axi_r_user  ),
  /* AW */
  .axi_aw_ready  (axi_aw_ready  ),       
  .axi_aw_valid  (axi_aw_valid  ),   
  .axi_aw_addr   (axi_aw_addr   ),   
  .axi_aw_prot   (axi_aw_prot   ),   
  .axi_aw_id     (axi_aw_id     ),
  .axi_aw_user   (axi_aw_user   ),     
  .axi_aw_len    (axi_aw_len    ),      
  .axi_aw_size   (axi_aw_size   ),
  .axi_aw_burst  (axi_aw_burst  ),
  .axi_aw_lock   (axi_aw_lock   ),   
  .axi_aw_cache  (axi_aw_cache  ),   
  .axi_aw_qos    (axi_aw_qos    ),   
  /* W */
  .axi_w_ready   (axi_w_ready ),  
  .axi_w_valid   (axi_w_valid ),
  .axi_w_data    (axi_w_data  ),   
  .axi_w_strb    (axi_w_strb  ),   
  .axi_w_last    (axi_w_last  ),   
  /* B */
  .axi_b_ready   (axi_b_ready),
  .axi_b_valid   (axi_b_valid),
  .axi_b_resp    (axi_b_resp ),  
  .axi_b_id      (axi_b_id   ),
  .axi_b_user    (axi_b_user )  
);

difftest_mem mem(
    .clk (clock),
    .rst (reset),

    .s_axi_awid    ( axi_aw_id    ),
    .s_axi_awaddr  ( axi_aw_addr  ),
    .s_axi_awlen   ( axi_aw_len   ),
    .s_axi_awsize  ( axi_aw_size  ),
    .s_axi_awburst ( axi_aw_burst ),
    .s_axi_awlock  ( axi_aw_lock  ),
    .s_axi_awcache ( axi_aw_cache ),
    .s_axi_awprot  ( axi_aw_prot  ),
    .s_axi_awvalid ( axi_aw_valid ),
    .s_axi_awready ( axi_aw_ready ),
    .s_axi_wdata   ( axi_w_data   ),
    .s_axi_wstrb   ( axi_w_strb   ),
    .s_axi_wlast   ( axi_w_last   ),
    .s_axi_wvalid  ( axi_w_valid  ),
    .s_axi_wready  ( axi_w_ready  ),
    .s_axi_bid     ( axi_b_id     ),
    .s_axi_bresp   ( axi_b_resp   ),
    .s_axi_bvalid  ( axi_b_valid  ),
    .s_axi_bready  ( axi_b_ready  ),
    .s_axi_arid    ( axi_ar_id    ),
    .s_axi_araddr  ( axi_ar_addr  ),
    .s_axi_arlen   ( axi_ar_len   ),
    .s_axi_arsize  ( axi_ar_size  ),
    .s_axi_arburst ( axi_ar_burst ),
    .s_axi_arlock  ( axi_ar_lock  ),
    .s_axi_arcache ( axi_ar_cache ),
    .s_axi_arprot  ( axi_ar_prot  ),
    .s_axi_arvalid ( axi_ar_valid ),
    .s_axi_arready ( axi_ar_ready ),
    .s_axi_rid     ( axi_r_id     ),
    .s_axi_rdata   ( axi_r_data   ),
    .s_axi_rresp   ( axi_r_resp   ),
    .s_axi_rlast   ( axi_r_last   ),
    .s_axi_rvalid  ( axi_r_valid  ),
    .s_axi_rready  ( axi_r_ready  )
);

endmodule

`resetall
`timescale 1ns / 1ps
`default_nettype none

/*
 * AXI4 RAM
 */
module difftest_mem #
(
    // Width of data bus in bits
    parameter DATA_WIDTH = 64,
    // Width of address bus in bits
    parameter ADDR_WIDTH = 30,
    // Width of wstrb (width of data bus in words)
    parameter STRB_WIDTH = (DATA_WIDTH/8),
    // Width of ID signal
    parameter ID_WIDTH = 4,
    // Extra pipeline register on output
    parameter PIPELINE_OUTPUT = 0
)
(
    input  wire                   clk,
    input  wire                   rst,

    input  wire [ID_WIDTH-1:0]    s_axi_awid,
    input  wire [ADDR_WIDTH-1:0]  s_axi_awaddr,
    input  wire [7:0]             s_axi_awlen,
    input  wire [2:0]             s_axi_awsize,
    input  wire [1:0]             s_axi_awburst,
    input  wire                   s_axi_awlock,
    input  wire [3:0]             s_axi_awcache,
    input  wire [2:0]             s_axi_awprot,
    input  wire                   s_axi_awvalid,
    output wire                   s_axi_awready,
    input  wire [DATA_WIDTH-1:0]  s_axi_wdata,
    input  wire [STRB_WIDTH-1:0]  s_axi_wstrb,
    input  wire                   s_axi_wlast,
    input  wire                   s_axi_wvalid,
    output wire                   s_axi_wready,
    output wire [ID_WIDTH-1:0]    s_axi_bid,
    output wire [1:0]             s_axi_bresp,
    output wire                   s_axi_bvalid,
    input  wire                   s_axi_bready,
    input  wire [ID_WIDTH-1:0]    s_axi_arid,
    input  wire [ADDR_WIDTH-1:0]  s_axi_araddr,
    input  wire [7:0]             s_axi_arlen,
    input  wire [2:0]             s_axi_arsize,
    input  wire [1:0]             s_axi_arburst,
    input  wire                   s_axi_arlock,
    input  wire [3:0]             s_axi_arcache,
    input  wire [2:0]             s_axi_arprot,
    input  wire                   s_axi_arvalid,
    output wire                   s_axi_arready,
    output wire [ID_WIDTH-1:0]    s_axi_rid,
    output wire [DATA_WIDTH-1:0]  s_axi_rdata,
    output wire [1:0]             s_axi_rresp,
    output wire                   s_axi_rlast,
    output wire                   s_axi_rvalid,
    input  wire                   s_axi_rready
);

parameter VALID_ADDR_WIDTH = ADDR_WIDTH - $clog2(STRB_WIDTH);
parameter WORD_WIDTH = STRB_WIDTH;
parameter WORD_SIZE = DATA_WIDTH/WORD_WIDTH;

// bus width assertions
initial begin
    if (WORD_SIZE * STRB_WIDTH != DATA_WIDTH) begin
        $error("Error: AXI data width not evenly divisble (instance %m)");
        $finish;
    end

    if (2**$clog2(WORD_WIDTH) != WORD_WIDTH) begin
        $error("Error: AXI word width must be even power of two (instance %m)");
        $finish;
    end
end

localparam [0:0]
    READ_STATE_IDLE = 1'd0,
    READ_STATE_BURST = 1'd1;

reg [0:0] read_state_reg = READ_STATE_IDLE, read_state_next;

localparam [1:0]
    WRITE_STATE_IDLE = 2'd0,
    WRITE_STATE_BURST = 2'd1,
    WRITE_STATE_RESP = 2'd2;

reg [1:0] write_state_reg = WRITE_STATE_IDLE, write_state_next;

reg mem_wr_en;
reg mem_rd_en;

reg [ID_WIDTH-1:0] read_id_reg = {ID_WIDTH{1'b0}}, read_id_next;
reg [ADDR_WIDTH-1:0] read_addr_reg = {ADDR_WIDTH{1'b0}}, read_addr_next;
reg [7:0] read_count_reg = 8'd0, read_count_next;
reg [2:0] read_size_reg = 3'd0, read_size_next;
reg [1:0] read_burst_reg = 2'd0, read_burst_next;
reg [ID_WIDTH-1:0] write_id_reg = {ID_WIDTH{1'b0}}, write_id_next;
reg [ADDR_WIDTH-1:0] write_addr_reg = {ADDR_WIDTH{1'b0}}, write_addr_next;
reg [7:0] write_count_reg = 8'd0, write_count_next;
reg [2:0] write_size_reg = 3'd0, write_size_next;
reg [1:0] write_burst_reg = 2'd0, write_burst_next;

reg s_axi_awready_reg = 1'b0, s_axi_awready_next;
reg s_axi_wready_reg = 1'b0, s_axi_wready_next;
reg [ID_WIDTH-1:0] s_axi_bid_reg = {ID_WIDTH{1'b0}}, s_axi_bid_next;
reg s_axi_bvalid_reg = 1'b0, s_axi_bvalid_next;
reg s_axi_arready_reg = 1'b0, s_axi_arready_next;
reg [ID_WIDTH-1:0] s_axi_rid_reg = {ID_WIDTH{1'b0}}, s_axi_rid_next;
reg [DATA_WIDTH-1:0] s_axi_rdata_reg = {DATA_WIDTH{1'b0}}, s_axi_rdata_next;
reg s_axi_rlast_reg = 1'b0, s_axi_rlast_next;
reg s_axi_rvalid_reg = 1'b0, s_axi_rvalid_next;
reg [ID_WIDTH-1:0] s_axi_rid_pipe_reg = {ID_WIDTH{1'b0}};
reg [DATA_WIDTH-1:0] s_axi_rdata_pipe_reg = {DATA_WIDTH{1'b0}};
reg s_axi_rlast_pipe_reg = 1'b0;
reg s_axi_rvalid_pipe_reg = 1'b0;

// `ifndef USE_DPIC_DDR
// // (* RAM_STYLE="BLOCK" *)
// reg [DATA_WIDTH-1:0] mem[(2**VALID_ADDR_WIDTH)-1:0];
// `endif

wire [VALID_ADDR_WIDTH-1:0] s_axi_awaddr_valid = s_axi_awaddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] s_axi_araddr_valid = s_axi_araddr >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] read_addr_valid = read_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);
wire [VALID_ADDR_WIDTH-1:0] write_addr_valid = write_addr_reg >> (ADDR_WIDTH - VALID_ADDR_WIDTH);

assign s_axi_awready = s_axi_awready_reg;
assign s_axi_wready = s_axi_wready_reg;
assign s_axi_bid = s_axi_bid_reg;
assign s_axi_bresp = 2'b00;
assign s_axi_bvalid = s_axi_bvalid_reg;
assign s_axi_arready = s_axi_arready_reg;
assign s_axi_rid = PIPELINE_OUTPUT ? s_axi_rid_pipe_reg : s_axi_rid_reg;
assign s_axi_rdata = PIPELINE_OUTPUT ? s_axi_rdata_pipe_reg : s_axi_rdata_reg;
assign s_axi_rresp = 2'b00;
assign s_axi_rlast = PIPELINE_OUTPUT ? s_axi_rlast_pipe_reg : s_axi_rlast_reg;
assign s_axi_rvalid = PIPELINE_OUTPUT ? s_axi_rvalid_pipe_reg : s_axi_rvalid_reg;

// `ifndef USE_DPIC_DDR
// integer i, j;
// initial begin
//     // two nested loops for smaller number of iterations per loop
//     // workaround for synthesizer complaints about large loop counts
//     for (i = 0; i < 2**VALID_ADDR_WIDTH; i = i + 2**(VALID_ADDR_WIDTH/2)) begin
//         for (j = i; j < i + 2**(VALID_ADDR_WIDTH/2); j = j + 1) begin
//             mem[j] = 0;
//         end
//     end
// end
// `endif

always @* begin
    write_state_next = WRITE_STATE_IDLE;

    mem_wr_en = 1'b0;

    write_id_next = write_id_reg;
    write_addr_next = write_addr_reg;
    write_count_next = write_count_reg;
    write_size_next = write_size_reg;
    write_burst_next = write_burst_reg;

    s_axi_awready_next = 1'b0;
    s_axi_wready_next = 1'b0;
    s_axi_bid_next = s_axi_bid_reg;
    s_axi_bvalid_next = s_axi_bvalid_reg && !s_axi_bready;

    case (write_state_reg)
        WRITE_STATE_IDLE: begin
            s_axi_awready_next = 1'b1;

            if (s_axi_awready && s_axi_awvalid) begin
                write_id_next = s_axi_awid;
                write_addr_next = s_axi_awaddr;
                write_count_next = s_axi_awlen;
                write_size_next = s_axi_awsize < $clog2(STRB_WIDTH) ? s_axi_awsize : $clog2(STRB_WIDTH);
                write_burst_next = s_axi_awburst;

                s_axi_awready_next = 1'b0;
                s_axi_wready_next = 1'b1;
                write_state_next = WRITE_STATE_BURST;
            end else begin
                write_state_next = WRITE_STATE_IDLE;
            end
        end
        WRITE_STATE_BURST: begin
            s_axi_wready_next = 1'b1;

            if (s_axi_wready && s_axi_wvalid) begin
                mem_wr_en = 1'b1;
                if (write_burst_reg != 2'b00) begin
                    write_addr_next = write_addr_reg + (1 << write_size_reg);
                end
                write_count_next = write_count_reg - 1;
                if (write_count_reg > 0) begin
                    write_state_next = WRITE_STATE_BURST;
                end else begin
                    s_axi_wready_next = 1'b0;
                    if (s_axi_bready || !s_axi_bvalid) begin
                        s_axi_bid_next = write_id_reg;
                        s_axi_bvalid_next = 1'b1;
                        s_axi_awready_next = 1'b1;
                        write_state_next = WRITE_STATE_IDLE;
                    end else begin
                        write_state_next = WRITE_STATE_RESP;
                    end
                end
            end else begin
                write_state_next = WRITE_STATE_BURST;
            end
        end
        WRITE_STATE_RESP: begin
            if (s_axi_bready || !s_axi_bvalid) begin
                s_axi_bid_next = write_id_reg;
                s_axi_bvalid_next = 1'b1;
                s_axi_awready_next = 1'b1;
                write_state_next = WRITE_STATE_IDLE;
            end else begin
                write_state_next = WRITE_STATE_RESP;
            end
        end
        default:write_state_next=WRITE_STATE_IDLE;
    endcase
end

always @(posedge clk) begin
    write_state_reg <= write_state_next;

    write_id_reg <= write_id_next;
    write_addr_reg <= write_addr_next;
    write_count_reg <= write_count_next;
    write_size_reg <= write_size_next;
    write_burst_reg <= write_burst_next;

    s_axi_awready_reg <= s_axi_awready_next;
    s_axi_wready_reg <= s_axi_wready_next;
    s_axi_bid_reg <= s_axi_bid_next;
    s_axi_bvalid_reg <= s_axi_bvalid_next;

// `ifdef USE_DPIC_DDR
    ram_write_helper(write_addr_valid, s_axi_wdata, 
    {{8{s_axi_wstrb[7]}},
     {8{s_axi_wstrb[6]}},
     {8{s_axi_wstrb[5]}},
     {8{s_axi_wstrb[4]}},
     {8{s_axi_wstrb[3]}},
     {8{s_axi_wstrb[2]}},
     {8{s_axi_wstrb[1]}},
     {8{s_axi_wstrb[0]}}}
    , mem_wr_en);
// `else
//     for (i = 0; i < WORD_WIDTH; i = i + 1) begin
//         if (mem_wr_en & s_axi_wstrb[i]) begin
//             mem[write_addr_valid][WORD_SIZE*i +: WORD_SIZE] <= s_axi_wdata[WORD_SIZE*i +: WORD_SIZE];
            
//         end
//     end
// `endif

    if (rst) begin
        write_state_reg <= WRITE_STATE_IDLE;

        s_axi_awready_reg <= 1'b0;
        s_axi_wready_reg <= 1'b0;
        s_axi_bvalid_reg <= 1'b0;
    end
end

always @* begin
    read_state_next = READ_STATE_IDLE;

    mem_rd_en = 1'b0;

    s_axi_rid_next = s_axi_rid_reg;
    s_axi_rlast_next = s_axi_rlast_reg;
    s_axi_rvalid_next = s_axi_rvalid_reg && !(s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg));

    read_id_next = read_id_reg;
    read_addr_next = read_addr_reg;
    read_count_next = read_count_reg;
    read_size_next = read_size_reg;
    read_burst_next = read_burst_reg;

    s_axi_arready_next = 1'b0;

    case (read_state_reg)
        READ_STATE_IDLE: begin
            s_axi_arready_next = 1'b1;

            if (s_axi_arready && s_axi_arvalid) begin
                read_id_next = s_axi_arid;
                read_addr_next = s_axi_araddr;
                read_count_next = s_axi_arlen;
                read_size_next = s_axi_arsize < $clog2(STRB_WIDTH) ? s_axi_arsize : $clog2(STRB_WIDTH);
                read_burst_next = s_axi_arburst;

                s_axi_arready_next = 1'b0;
                read_state_next = READ_STATE_BURST;
            end else begin
                read_state_next = READ_STATE_IDLE;
            end
        end
        READ_STATE_BURST: begin
            if (s_axi_rready || (PIPELINE_OUTPUT && !s_axi_rvalid_pipe_reg) || !s_axi_rvalid_reg) begin
                mem_rd_en = 1'b1;
                s_axi_rvalid_next = 1'b1;
                s_axi_rid_next = read_id_reg;
                s_axi_rlast_next = read_count_reg == 0;
                if (read_burst_reg != 2'b00) begin
                    read_addr_next = read_addr_reg + (1 << read_size_reg);
                end
                read_count_next = read_count_reg - 1;
                if (read_count_reg > 0) begin
                    read_state_next = READ_STATE_BURST;
                end else begin
                    s_axi_arready_next = 1'b1;
                    read_state_next = READ_STATE_IDLE;
                end
            end else begin
                read_state_next = READ_STATE_BURST;
            end
        end
    endcase
end

always @(posedge clk) begin
    read_state_reg <= read_state_next;

    read_id_reg <= read_id_next;
    read_addr_reg <= read_addr_next;
    read_count_reg <= read_count_next;
    read_size_reg <= read_size_next;
    read_burst_reg <= read_burst_next;

    s_axi_arready_reg <= s_axi_arready_next;
    s_axi_rid_reg <= s_axi_rid_next;
    s_axi_rlast_reg <= s_axi_rlast_next;
    s_axi_rvalid_reg <= s_axi_rvalid_next;

// `ifdef USE_DPIC_DDR
    s_axi_rdata_reg <= ram_read_helper(mem_rd_en, read_addr_valid);
// `else 
//     if (mem_rd_en) begin
//         s_axi_rdata_reg <= mem[read_addr_valid];
//     end
// `endif

    if (!s_axi_rvalid_pipe_reg || s_axi_rready) begin
        s_axi_rid_pipe_reg <= s_axi_rid_reg;
        s_axi_rdata_pipe_reg <= s_axi_rdata_reg;
        s_axi_rlast_pipe_reg <= s_axi_rlast_reg;
        s_axi_rvalid_pipe_reg <= s_axi_rvalid_reg;
    end

    if (rst) begin
        read_state_reg <= READ_STATE_IDLE;

        s_axi_arready_reg <= 1'b0;
        s_axi_rvalid_reg <= 1'b0;
        s_axi_rvalid_pipe_reg <= 1'b0;
    end
end

endmodule

`resetall
